<!DOCTYPE html>
<html lang="en">
  <head>
    <title>
        Java-Se-NIO - rulerLwx Blog
      </title>
        <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    <meta name="viewport"
      content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no, minimal-ui">
    <meta name="renderer" content="webkit">
    <meta http-equiv="Cache-Control" content="no-transform" />
    <meta http-equiv="Cache-Control" content="no-siteapp" />
    <meta name="apple-mobile-web-app-capable" content="yes">
    <meta name="apple-mobile-web-app-status-bar-style" content="black">
    <meta name="format-detection" content="telephone=no,email=no,adress=no">
    
    <meta name="theme-color" content="#000000" />
    
    <meta http-equiv="window-target" content="_top" />
    
    
    <meta name="description" content="基本概念 通道 通道（Channel）是现代计算机的一个特性，用于源节点与目标节点之间的连接。它不能单独地使用，必须结合缓冲区（Buffer）一" />
    <meta name="generator" content="Hugo 0.73.0 with theme pure" />
    <title>Java-Se-NIO - rulerLwx Blog</title>
    
    
    <link rel="stylesheet" href="https://rulerLwx.gitee.io/css/style.min.c4bc7071f132c964c2116bca53b392933f377e5ca7b7051ed245187c621a2d3e.css">
    
    <link rel="stylesheet" href="https://cdn.staticfile.org/highlight.js/9.15.10/styles/github.min.css" async>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/tocbot/4.4.2/tocbot.css" async>
    <meta property="og:title" content="Java-Se-NIO" />
<meta property="og:description" content="基本概念 通道 通道（Channel）是现代计算机的一个特性，用于源节点与目标节点之间的连接。它不能单独地使用，必须结合缓冲区（Buffer）一" />
<meta property="og:type" content="article" />
<meta property="og:url" content="https://rulerLwx.gitee.io/2020/07/java-se-nio/" />
<meta property="article:published_time" content="2020-07-01T18:58:47+08:00" />
<meta property="article:modified_time" content="2020-07-01T18:58:47+08:00" />
<meta itemprop="name" content="Java-Se-NIO">
<meta itemprop="description" content="基本概念 通道 通道（Channel）是现代计算机的一个特性，用于源节点与目标节点之间的连接。它不能单独地使用，必须结合缓冲区（Buffer）一">
<meta itemprop="datePublished" content="2020-07-01T18:58:47&#43;08:00" />
<meta itemprop="dateModified" content="2020-07-01T18:58:47&#43;08:00" />
<meta itemprop="wordCount" content="4219">



<meta itemprop="keywords" content="," /><meta name="twitter:card" content="summary"/>
<meta name="twitter:title" content="Java-Se-NIO"/>
<meta name="twitter:description" content="基本概念 通道 通道（Channel）是现代计算机的一个特性，用于源节点与目标节点之间的连接。它不能单独地使用，必须结合缓冲区（Buffer）一"/>

    <!--[if lte IE 9]>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/classlist/1.1.20170427/classList.min.js"></script>
      <![endif]-->

    <!--[if lt IE 9]>
        <script src="https://cdn.jsdelivr.net/npm/html5shiv@3.7.3/dist/html5shiv.min.js"></script>
        <script src="https://cdn.jsdelivr.net/npm/respond.js@1.4.2/dest/respond.min.js"></script>
      <![endif]-->
  </head>

  
  

  <body class="main-center theme-black" itemscope itemtype="http://schema.org/WebPage"><header class="header" itemscope itemtype="http://schema.org/WPHeader">
    <div class="slimContent">
      <div class="navbar-header">
        <div class="profile-block text-center">
          <a id="avatar" href="https://gitee.com/rulerLwx" target="_blank">
            <img class="img-circle img-rotate" src="https://rulerLwx.gitee.io/avatar.png" width="200" height="200">
          </a>
          <h2 id="name" class="hidden-xs hidden-sm">rulerLwx</h2>
          <h3 id="title" class="hidden-xs hidden-sm hidden-md">thinking...</h3>
          <small id="location" class="text-muted hidden-xs hidden-sm"><i class="icon icon-map-marker"></i>Guangzhou, China</small>
        </div><div class="search" id="search-form-wrap">
    <form class="search-form sidebar-form">
        <div class="input-group">
            <input type="text" class="search-form-input form-control" placeholder="Search" />
            <span class="input-group-btn">
                <button type="submit" class="search-form-submit btn btn-flat" onclick="return false;"><i
                        class="icon icon-search"></i></button>
            </span>
        </div>
        <div class="ins-search">
            <div class="ins-search-mask"></div>
            <div class="ins-search-container">
                <div class="ins-input-wrapper">
                    <input type="text" class="ins-search-input" placeholder="Type something..."
                        x-webkit-speech />
                    <button type="button" class="close ins-close ins-selectable" data-dismiss="modal"
                        aria-label="Close"><span aria-hidden="true">×</span></button>
                </div>
                <div class="ins-section-wrapper">
                    <div class="ins-section-container"></div>
                </div>
            </div>
        </div>
    </form>
</div>
        <button class="navbar-toggle collapsed" type="button" data-toggle="collapse" data-target="#main-navbar" aria-controls="main-navbar" aria-expanded="false">
          <span class="sr-only">Toggle navigation</span>
          <span class="icon-bar"></span>
          <span class="icon-bar"></span>
          <span class="icon-bar"></span>
        </button>
      </div>
      <nav id="main-navbar" class="collapse navbar-collapse" itemscope itemtype="http://schema.org/SiteNavigationElement" role="navigation">
        <ul class="nav navbar-nav main-nav">
            <li class="menu-item menu-item-home">
                <a href="/">
                    <i class="icon icon-home-fill"></i>
                  <span class="menu-title">Home</span>
                </a>
            </li>
            <li class="menu-item menu-item-archives">
                <a href="/posts/">
                    <i class="icon icon-archives-fill"></i>
                  <span class="menu-title">Archives</span>
                </a>
            </li>
            <li class="menu-item menu-item-categories">
                <a href="/categories/">
                    <i class="icon icon-folder"></i>
                  <span class="menu-title">Categories</span>
                </a>
            </li>
            <li class="menu-item menu-item-tags">
                <a href="/tags/">
                    <i class="icon icon-tags"></i>
                  <span class="menu-title">Tags</span>
                </a>
            </li>
            <li class="menu-item menu-item-about">
                <a href="/about/">
                    <i class="icon icon-cup-fill"></i>
                  <span class="menu-title">About</span>
                </a>
            </li>
        </ul>
      </nav>
    </div>
  </header>

<aside class="sidebar" itemscope itemtype="http://schema.org/WPSideBar">
  <div class="slimContent">
    
      <div class="widget">
    <h3 class="widget-title">Board</h3>
    <div class="widget-body">
        <div id="board">
            <div class="content">enjoy~
            </div>
        </div>
    </div>
</div>

      <div class="widget">
    <h3 class="widget-title"> Categories</h3>
    <div class="widget-body">
        <ul class="category-list">
            <li class="category-list-item"><a href="https://rulerLwx.gitee.io/categories/java-framework/" class="category-list-link">java-framework</a><span class="category-list-count">38</span></li>
            <li class="category-list-item"><a href="https://rulerLwx.gitee.io/categories/java-front-end/" class="category-list-link">java-front-end</a><span class="category-list-count">11</span></li>
            <li class="category-list-item"><a href="https://rulerLwx.gitee.io/categories/java-se/" class="category-list-link">java-se</a><span class="category-list-count">21</span></li>
            <li class="category-list-item"><a href="https://rulerLwx.gitee.io/categories/java-senior/" class="category-list-link">java-senior</a><span class="category-list-count">4</span></li>
            <li class="category-list-item"><a href="https://rulerLwx.gitee.io/categories/linux/" class="category-list-link">linux</a><span class="category-list-count">13</span></li>
            <li class="category-list-item"><a href="https://rulerLwx.gitee.io/categories/tools/" class="category-list-link">tools</a><span class="category-list-count">1</span></li>
            <li class="category-list-item"><a href="https://rulerLwx.gitee.io/categories/%E6%8A%80%E6%9C%AF%E6%9D%82%E7%83%A9/" class="category-list-link">技术杂烩</a><span class="category-list-count">4</span></li>
            <li class="category-list-item"><a href="https://rulerLwx.gitee.io/categories/%E6%95%B0%E6%8D%AE%E5%BA%93/" class="category-list-link">数据库</a><span class="category-list-count">15</span></li>
        </ul>
    </div>
</div>
      <div class="widget">
    <h3 class="widget-title"> Tags</h3>
    <div class="widget-body">
        <ul class="tag-list">
            
            
            <li class="tag-list-item"><a href="https://rulerLwx.gitee.io/tags/jvm/" class="tag-list-link">jvm</a><span
                    class="tag-list-count">1</span></li>
            
            
            <li class="tag-list-item"><a href="https://rulerLwx.gitee.io/tags/%E5%A4%9A%E7%BA%BF%E7%A8%8B/" class="tag-list-link">多线程</a><span
                    class="tag-list-count">2</span></li>
            
            
            <li class="tag-list-item"><a href="https://rulerLwx.gitee.io/tags/%E7%BD%91%E7%BB%9C%E7%BC%96%E7%A8%8B/" class="tag-list-link">网络编程</a><span
                    class="tag-list-count">3</span></li>
            
        </ul>

    </div>
</div>
      
<div class="widget">
    <h3 class="widget-title">Recent Posts</h3>
    <div class="widget-body">
        <ul class="recent-post-list list-unstyled no-thumbnail">
            <li>
                <div class="item-inner">
                    <p class="item-title">
                        <a href="https://rulerLwx.gitee.io/2020/07/%E8%87%AA%E5%B7%B1%E5%8A%A8%E6%89%8B%E4%B8%80%E6%89%B9%E9%87%8F%E7%A7%BB%E5%8A%A8%E9%87%8D%E5%91%BD%E5%90%8D%E6%96%87%E4%BB%B6/" class="title">自己动手（一）——批量移动、重命名文件</a>
                    </p>
                    <p class="item-date">
                        <time datetime="2020-07-27 17:50:02 &#43;0800 CST" itemprop="datePublished">2020-07-27</time>
                    </p>
                </div>
            </li>
            <li>
                <div class="item-inner">
                    <p class="item-title">
                        <a href="https://rulerLwx.gitee.io/2020/07/%E5%85%B3%E4%BA%8Einteger%E7%9A%84-128~127%E7%BC%93%E5%AD%98/" class="title">关于Integer的 -128~127缓存</a>
                    </p>
                    <p class="item-date">
                        <time datetime="2020-07-11 16:56:21 &#43;0800 CST" itemprop="datePublished">2020-07-11</time>
                    </p>
                </div>
            </li>
            <li>
                <div class="item-inner">
                    <p class="item-title">
                        <a href="https://rulerLwx.gitee.io/2020/07/%E8%B7%A8%E5%9F%9F%E9%97%AE%E9%A2%98/" class="title">跨域问题</a>
                    </p>
                    <p class="item-date">
                        <time datetime="2020-07-08 22:41:12 &#43;0800 CST" itemprop="datePublished">2020-07-08</time>
                    </p>
                </div>
            </li>
            <li>
                <div class="item-inner">
                    <p class="item-title">
                        <a href="https://rulerLwx.gitee.io/2020/07/%E4%B8%AA%E4%BA%BA%E5%8D%9A%E5%AE%A2%E6%90%AD%E5%BB%BA/" class="title">个人博客搭建</a>
                    </p>
                    <p class="item-date">
                        <time datetime="2020-07-05 18:58:47 &#43;0800 CST" itemprop="datePublished">2020-07-05</time>
                    </p>
                </div>
            </li>
            <li>
                <div class="item-inner">
                    <p class="item-title">
                        <a href="https://rulerLwx.gitee.io/2020/07/centos/" class="title">CentOS-</a>
                    </p>
                    <p class="item-date">
                        <time datetime="2020-07-01 18:58:47 &#43;0800 CST" itemprop="datePublished">2020-07-01</time>
                    </p>
                </div>
            </li>
        </ul>
    </div>
</div>
  </div>
</aside>

    
    
<aside class="sidebar sidebar-toc collapse" id="collapseToc" itemscope itemtype="http://schema.org/WPSideBar">
  <div class="slimContent">
    <h4 class="toc-title">Catalogue</h4>
    <nav id="toc" class="js-toc toc">

    </nav>
  </div>
</aside>
<main class="main" role="main"><div class="content">
  <article id="-" class="article article-type-" itemscope
    itemtype="http://schema.org/BlogPosting">
    
    <div class="article-header">
      <h1 itemprop="name">
  <a
    class="article-title"
    href="/2020/07/java-se-nio/"
    >Java-Se-NIO</a
  >
</h1>

      <div class="article-meta">
        
<span class="article-date">
  <i class="icon icon-calendar-check"></i>&nbsp;
<a href="https://rulerLwx.gitee.io/2020/07/java-se-nio/" class="article-date">
  <time datetime="2020-07-01 18:58:47 &#43;0800 CST" itemprop="datePublished">2020-07-01</time>
</a>
</span>
<span class="article-category">
  <i class="icon icon-folder"></i>&nbsp;
  <a class="article-category-link" href="/categories/java-se/"> Java-Se </a>
</span>  
  <span class="article-tag">
    <i class="icon icon-tags"></i>&nbsp;
    <a class="article-tag-link" href="/tags//">  </a>
  </span>

        <span class="post-comment"><i class="icon icon-comment"></i>&nbsp;<a href="/2020/07/java-se-nio/#comments"
            class="article-comment-link">Comments</a></span>
		<span class="post-wordcount hidden-xs" itemprop="wordCount">Word Count: 4219words</span>
		<span class="post-readcount hidden-xs" itemprop="timeRequired">Read Count: 9minutes </span>
      </div>
    </div>
    <div class="article-entry marked-body js-toc-content" itemprop="articleBody">
      <h1 id="基本概念">基本概念</h1>
<h2 id="通道">通道</h2>
<p>通道（Channel）是现代计算机的一个特性，用于源节点与目标节点之间的连接。它不能单独地使用，必须结合缓冲区（Buffer）一起使用。通道就像一条条高速公路，而缓冲区就是在高速公路上跑的一输输车。通道是双向的，既可读，也可写。</p>
<p>常用的通道有：</p>
<ul>
<li>FileChannel</li>
<li>SocketChannel</li>
<li>ServerSocketChannel</li>
<li>DatagramChannel</li>
</ul>
<hr>
<p>获取通道的方式有：</p>
<ul>
<li>RandomAccessFile/FileInputStream/FileOutputStream对象上调用getChannel方法来获取。</li>
<li>FileChannel/SocketChannel/ServerSocketChannel/DatagramChannel等调用自身的静态方法open()来获取。</li>
</ul>
<hr>
<p>Channel中最常用的方法:</p>
<ul>
<li>map()，将Channel对应的部分或全部数据映射成ByteBuffer（MappedByteBuffer）.也叫内存映射。</li>
<li>read()，读取数据。</li>
<li>wirte()，写入数据。</li>
</ul>
<h2 id="缓冲区">缓冲区</h2>
<p>缓冲区（Buffer）可以理解成一个容器（本质上是个数组），可以保存多个类型相同的数据。</p>
<p>常用的缓冲区有：</p>
<ul>
<li>ByteBuffer</li>
<li>CharBuffer</li>
<li>ShortBuffer</li>
<li>IntBuffer</li>
<li>LongBuffer</li>
<li>FloadBuffer</li>
<li>DoubleBuffer</li>
<li>MappedByteBuffer</li>
</ul>
<hr>
<p>创建缓冲区的方式：</p>
<ul>
<li>调用缓冲区本身的静态方法 <code>static XxxBuffer allocate(int capacity)</code>.将缓冲区建立在JVM内存中。</li>
<li>调用缓冲区本身的静态方法 <code>static XxxBuffer allocateDirect(int capacity)</code>（只限ByteBuffer，其它的不能使用此方法）.将缓冲区建立在物理内存中，提高效率，但不安全、资源消耗大。</li>
</ul>
<hr>
<p>缓冲区中，要搞清楚四个常量及它们之间的关系：</p>
<p><code>0 &lt;= mark &lt;= position &lt;= limit &lt;= capacity </code></p>
<p>Buffer中有两个重要的方法：</p>
<ul>
<li>flip()，将写状态转为读状态  （limit=position,limit~capacity之间的数据被封印起来）</li>
<li>clear()，将读状态转为写状态 （position=0，limit = capacity，但前一个缓冲区的数据并没有立即被清除。只有当前存入的位置的值被替换）</li>
</ul>
<p>Buffer的其它常用方法：</p>
<ul>
<li>put()：将数据放入Buffer。</li>
<li>get()：从Buffer中取出数据。</li>
<li>Buffer mark()：设置mark位置，mark = position;。</li>
<li>Buffer reset()：将position转到mark所在位置，position = mark;。</li>
<li>Buffer rewind()：将position设为0，取消设置mark。</li>
</ul>
<h2 id="选择器">选择器</h2>
<p>选择器（Selector）是 SelectableChannel对象的多路复用器，所有希望采用非阻塞方式进行通信的Channel都应该注册到Selector对象。</p>
<p>创建 Selector实例的方法：调用Selector类的<code>open()</code>静态方法</p>
<h2 id="charset">Charset</h2>
<p>二进制与字符之间的转换</p>
<pre><code>Charset cn = Charset.forName(&quot;GBK&quot;);
ByteBuffer byteBuffer = cn.encode(&quot;&quot;); //将字符串转换成二进制
CharBuffer charBuffer = cn.decode(java.nio.ByteBuffer bb); //将二进制转换成字符

</code></pre>
<h1 id="通道缓冲区的使用">通道、缓冲区的使用</h1>
<h2 id="filechannel">FileChannel</h2>
<p>1、Channel的map()方法是将对应的部分或全部数据映射成ByteBuffer（MappedByteBuffer），即内存映射，此种方式对大文件的操作可能会影响系统性能。</p>
<p>Channel的map()方法跟Buffer的allocateDirect(int capacity)原理一样。</p>
<pre><code>public class FileChannelTest{
    public static void main(String[] args){
        File f = new File(&quot;FileChannelTest.java&quot;);
        try(
            // 创建FileInputStream，以该文件输入流创建FileChannel
            FileChannel inChannel = new FileInputStream(f).getChannel();
            // 以文件输出流创建FileBuffer，用以控制输出
            FileChannel outChannel = new FileOutputStream(&quot;a.txt&quot;).getChannel())
        {
            // 将FileChannel里的全部数据映射成ByteBuffer
            MappedByteBuffer buffer = inChannel.map(FileChannel.MapMode.READ_ONLY , 0 , f.length());   // ①
            // 使用GBK的字符集来创建解马器
            Charset charset = Charset.forName(&quot;GBK&quot;);
            // 直接将buffer里的数据全部输出
            outChannel.write(buffer);     // ②
            // 再次调用buffer的clear()方法，复原limit、position的位置
            buffer.clear();
            // 创建解马器(CharsetDecoder)对象
            CharsetDecoder decoder = charset.newDecoder();
            // 使用解马器将ByteBuffer转换成CharBuffer
            CharBuffer charBuffer =  decoder.decode(buffer);
            // CharBuffer的toString方法可以获取对应的字符串
            System.out.println(charBuffer);
        }
        catch (IOException ex){
            ex.printStackTrace();
        }
    }
}

</code></pre>
<p>2、Channel的read()、write()方法可以实现“竹筒重复取水”方式，大小文件都可以操作。</p>
<pre><code>public class ReadFile{
    public static void main(String[] args) throws IOException {
        try(
            // 创建文件输入流
            FileInputStream fis = new FileInputStream(&quot;ReadFile.java&quot;);
            // 创建一个FileChannel
            FileChannel fcin = fis.getChannel())
        {
            // 定义一个ByteBuffer对象，用于重复取水
            ByteBuffer bbuff = ByteBuffer.allocate(256);
            // 将FileChannel中数据放入ByteBuffer中
            while( fcin.read(bbuff) != -1 )
            {
                // 锁定Buffer的空白区
                bbuff.flip();
                // 创建Charset对象
                Charset charset = Charset.forName(&quot;GBK&quot;);
                // 创建解马器(CharsetDecoder)对象
                CharsetDecoder decoder = charset.newDecoder();
                // 将ByteBuffer的内容转码
                CharBuffer cbuff = decoder.decode(bbuff);
                System.out.print(cbuff);
                // 将Buffer初始化，为下一次读取数据做准备
                bbuff.clear();
            }
        }
    }
}

</code></pre>
<h1 id="选择器的使用">选择器的使用</h1>
<p>选择器（Selector）可以同时监控多个 SelectableChannel 的IO状况，是非阻塞式的核心。</p>
<pre><code>java.nio.channels.Channel
                   |-SelectableChannel
                        |-SocketChannel
                        |-ServerSocketChannel
                        |-DatagramChannel

                        |-Pipe.SinkChannel, 
                        |-Pipe.SourceChannel
</code></pre>
<hr>
<p>Selector实例通过 Selector.open()获取，其实例的常用如下方法：</p>
<ul>
<li>keys(),返回SelectionKey集合，代表所有注册在该 Selector上的所有Channel</li>
<li>selectedKey,返回SelectionKey集合，代表该 Selector上需要进行IO处理的Channel</li>
<li>select()，监控Channel,当有需要处理的IO操作的Channel时，返回这此Channel的数量</li>
<li>selectNow()，同select()，只是不阻塞线程</li>
</ul>
<hr>
<p>SelectableChannel 常用如下方法：</p>
<ul>
<li>register()，将其注册到指定的Selector上</li>
<li>configureBlocking(boolean block)，是否采用阻塞模式（所有的 Channel默认都是阻塞式）</li>
<li>isBlocking()，是否是阻塞模式</li>
<li>vilidOps，返回一个整数值，表示所支持的IO操作</li>
</ul>
<hr>
<p>阻塞与非阻塞</p>
<ul>
<li>FileChannel不可用于非阻塞式，不可注册到Selector</li>
</ul>
<p>通过通道（Channel）来控制阻塞与非阻塞：</p>
<pre><code class="language-java">        channel.configureBlocking(false);
</code></pre>
<h2 id="阻塞--非阻塞异步--同步">阻塞 &amp;&amp; 非阻塞、异步 &amp;&amp; 同步</h2>
<p>参看《Java-Se-网络编程.docx》</p>
<hr>
<h2 id="server">Server</h2>
<p>地址和端口包装成了一个单独的对象：InetSocketAddress。</p>
<p>创建一个ServerSocketChannel的代码片段如下：</p>
<pre><code>        ServerSocketChannel server = ServerSocketChannel.open();
        InetSocketAddress isa = new InetSocketAddress(&quot;127.0.0.1&quot;, 30000);
        server.bind(isa);
</code></pre>
<p>将该Channel注册到指定Selector上的代码片段如下：</p>
<pre><code>        Selector selector = Selector.open();

        server.configureBlocking(false);
        server.register(selector,SelectionKey.OP_ACCEPT);
</code></pre>
<p>Server完整示例如下：</p>
<pre><code class="language-java">public class NServer
{
    // 用于检测所有Channel状态的Selector
    private Selector selector = null;
    static final int PORT = 30000;
    // 定义实现编码、解码的字符集对象
    private Charset charset = Charset.forName(&quot;UTF-8&quot;);
    public void init()throws IOException
    {
        selector = Selector.open();
        // 通过open方法来打开一个未绑定的ServerSocketChannel实例
        ServerSocketChannel server = ServerSocketChannel.open();
        InetSocketAddress isa = new InetSocketAddress(&quot;127.0.0.1&quot;, PORT);
        // 将该ServerSocketChannel绑定到指定IP地址
        server.bind(isa);
        // 设置ServerSocket以非阻塞方式工作
        server.configureBlocking(false);
        // 将server注册到指定Selector对象
        server.register(selector, SelectionKey.OP_ACCEPT);
        while (selector.select() &gt; 0)
        {
            // 依次处理selector上的每个已选择的SelectionKey
            for (SelectionKey sk : selector.selectedKeys())
            {
                // 从selector上的已选择Key集中删除正在处理的SelectionKey
                selector.selectedKeys().remove(sk);      // ①
                // 如果sk对应的Channel包含客户端的连接请求
                if (sk.isAcceptable())        // ②
                {
                    // 调用accept方法接受连接，产生服务器端的SocketChannel
                    SocketChannel sc = server.accept();
                    // 设置采用非阻塞模式
                    sc.configureBlocking(false);
                    // 将该SocketChannel也注册到selector
                    sc.register(selector, SelectionKey.OP_READ);
                    // 将sk对应的Channel设置成准备接受其他请求
                    sk.interestOps(SelectionKey.OP_ACCEPT);
                }
                // 如果sk对应的Channel有数据需要读取
                if (sk.isReadable())     // ③
                {
                    // 获取该SelectionKey对应的Channel，该Channel中有可读的数据
                    SocketChannel sc = (SocketChannel)sk.channel();
                    // 定义准备执行读取数据的ByteBuffer
                    ByteBuffer buff = ByteBuffer.allocate(1024);
                    String content = &quot;&quot;;
                    // 开始读取数据
                    try
                    {
                        while(sc.read(buff) &gt; 0)
                        {
                            buff.flip();
                            content += charset.decode(buff);
                        }
                        // 打印从该sk对应的Channel里读取到的数据
                        System.out.println(&quot;读取的数据：&quot; + content);
                        // 将sk对应的Channel设置成准备下一次读取
                        sk.interestOps(SelectionKey.OP_READ);
                    }
                    // 如果捕捉到该sk对应的Channel出现了异常，即表明该Channel
                    // 对应的Client出现了问题，所以从Selector中取消sk的注册
                    catch (IOException ex)
                    {
                        // 从Selector中删除指定的SelectionKey
                        sk.cancel();
                        if (sk.channel() != null)
                        {
                            sk.channel().close();
                        }
                    }
                    // 如果content的长度大于0，即聊天信息不为空
                    if (content.length() &gt; 0)
                    {
                        // 遍历该selector里注册的所有SelectionKey
                        for (SelectionKey key : selector.keys())
                        {
                            // 获取该key对应的Channel
                            Channel targetChannel = key.channel();
                            // 如果该channel是SocketChannel对象
                            if (targetChannel instanceof SocketChannel)
                            {
                                // 将读到的内容写入该Channel中
                                SocketChannel dest = (SocketChannel)targetChannel;
                                dest.write(charset.encode(content));
                            }
                        }
                    }
                }
            }
        }
    }
    public static void main(String[] args)
        throws IOException
    {
        new NServer().init();
    }
}

</code></pre>
<h2 id="client">Client</h2>
<pre><code>public class NClient {
    // 定义检测SocketChannel的Selector对象
    private Selector selector = null;
    static final int PORT = 30000;
    // 定义处理编码和解码的字符集
    private Charset charset = Charset.forName(&quot;UTF-8&quot;);
    // 客户端SocketChannel
    private SocketChannel sc = null;
    public void init()throws IOException
    {
        selector = Selector.open();
        InetSocketAddress isa = new InetSocketAddress(&quot;127.0.0.1&quot;, PORT);
        // 调用open静态方法创建连接到指定主机的SocketChannel
        sc = SocketChannel.open(isa);
        // 设置该sc以非阻塞方式工作
        sc.configureBlocking(false);
        // 将SocketChannel对象注册到指定Selector
        sc.register(selector, SelectionKey.OP_READ);
        // 启动读取服务器端数据的线程
        new ClientThread().start();
        // 创建键盘输入流
        Scanner scan = new Scanner(System.in);
        while (scan.hasNextLine())
        {
            // 读取键盘输入
            String line = scan.nextLine();
            // 将键盘输入的内容输出到SocketChannel中
            sc.write(charset.encode(line));
        }
    }
    // 定义读取服务器数据的线程
    private class ClientThread extends Thread
    {
        public void run()
        {
            try
            {
                while (selector.select() &gt; 0)    // ①
                {
                    // 遍历每个有可用IO操作Channel对应的SelectionKey
                    for (SelectionKey sk : selector.selectedKeys())
                    {
                        // 删除正在处理的SelectionKey
                        selector.selectedKeys().remove(sk);
                        // 如果该SelectionKey对应的Channel中有可读的数据
                        if (sk.isReadable())
                        {
                            // 使用NIO读取Channel中的数据
                            SocketChannel sc = (SocketChannel)sk.channel();
                            ByteBuffer buff = ByteBuffer.allocate(1024);
                            String content = &quot;&quot;;
                            while(sc.read(buff) &gt; 0)
                            {
                                sc.read(buff);
                                buff.flip();
                                content += charset.decode(buff);
                            }
                            // 打印输出读取的内容
                            System.out.println(&quot;聊天信息：&quot; + content);
                            // 为下一次读取作准备
                            sk.interestOps(SelectionKey.OP_READ);
                        }
                    }
                }
            }
            catch (IOException ex)
            {
                ex.printStackTrace();
            }
        }
    }
    public static void main(String[] args)
        throws IOException
    {
        new NClient().init();
    }
}

</code></pre>
<h1 id="分散与聚集">分散与聚集</h1>
<p>分散读取（Scattering Reads）：将通道中的数据分散到多个缓冲区中</p>
<p>聚集写入（Gathering Writes）：将多个缓冲区中的数据聚集到通道中</p>
<h2 id="分散读取">分散读取</h2>
<pre><code class="language-java">    public void tset() throws Exception {

        RandomAccessFile raf1 = new RandomAccessFile(&quot;a.txt&quot;, &quot;rw&quot;);

        FileChannel channel1 = raf1.getChannel();

        ByteBuffer buf1 = ByteBuffer.allocate(1024);
        ByteBuffer buf2 = ByteBuffer.allocate(1024);

        ByteBuffer[] bufs = {buf1,buf2};
        channel1.read(bufs);

        for(ByteBuffer b:bufs){
            b.flip();
        }

        System.out.println(new String(bufs[0].array(),0,bufs[0].limit()));
        System.out.println(&quot;----------------------&quot;);
        System.out.println(new String(bufs[1].array(),0,bufs[0].limit()));
    }
</code></pre>
<h2 id="聚集写入">聚集写入</h2>
<pre><code class="language-java">        RandomAccessFile raf2 = new RandomAccessFile(&quot;a.txt&quot;, &quot;rw&quot;);
        FileChannel channel2 = raf2.getChannel();
        channel2.write(bufs);
</code></pre>
<h1 id="java-se-nio2">Java-Se-NIO2</h1>
<p>jdk7提供： Path,Paths,Files,SimpleFileVisitor,WatchService</p>
<ul>
<li><code>Path path = Paths.get(&quot;pom.xml&quot;);</code>获取项目根路径下的文件，获取项目下的文件，如<code>Path path = Paths.get(&quot;log&quot;,&quot;pom.xml&quot;);</code>，可以可以指定路径，如<code>Path path = Paths.get(&quot;e:&quot;, &quot;project.properties&quot;);</code>.</li>
<li><code>SimpleFileVisitor</code>递归删除指定目录下的文件和文件，<strong>参考jdk中<code>FileVisitor</code>文档示例</strong>。</li>
<li><code>Files</code>实现文件的复制和删除。</li>
</ul>

    </div>
    <div class="article-footer">
<blockquote class="mt-2x">
  <ul class="post-copyright list-unstyled">
    <li class="post-copyright-link hidden-xs">
      <strong>Permalink: </strong>
      <a href="https://rulerLwx.gitee.io/2020/07/java-se-nio/" title="Java-Se-NIO" target="_blank" rel="external">https://rulerLwx.gitee.io/2020/07/java-se-nio/</a>
    </li>
    <li class="post-copyright-license">
      <strong>License：</strong><a href="http://creativecommons.org/licenses/by/4.0/deed.zh" target="_blank" rel="external">CC BY 4.0 CN</a>
    </li>
  </ul>
</blockquote>

<div class="panel panel-default panel-badger">
  <div class="panel-body">
    <figure class="media">
      <div class="media-left">
        <a href="https://gitee.com/rulerLwx" target="_blank" class="img-burn thumb-sm visible-lg">
          <img src="https://rulerLwx.gitee.io/avatar.png" class="img-rounded w-full" alt="">
        </a>
      </div>
      <div class="media-body">
        <h3 class="media-heading"><a href="https://gitee.com/rulerLwx" target="_blank"><span class="text-dark">rulerLwx</span><small class="ml-1x">thinking...</small></a></h3>
        <div>Good Good Study, Day Day Up~</div>
      </div>
    </figure>
  </div>
</div>
    </div>
  </article>
<section id="comments">
    <div id="vcomments"></div>
</section>

</div><nav class="bar bar-footer clearfix" data-stick-bottom>
    <div class="bar-inner">
        <ul class="pager pull-left">
            <li class="prev">
                <a href="https://rulerLwx.gitee.io/2020/07/java-se-%E4%BB%A3%E7%90%86/" title="Java-Se-代理"><i
                        class="icon icon-angle-left"
                        aria-hidden="true"></i><span>&nbsp;&nbsp;Older</span></a>
            </li>
            <li class="next">
                <a href="https://rulerLwx.gitee.io/2020/07/java-se-java8/"
                    title="Java-Se-Java8"><span>Newer&nbsp;&nbsp;</span><i
                        class="icon icon-angle-right" aria-hidden="true"></i></a>
            </li>
            
            <li class="toggle-toc">
                <a class="toggle-btn collapsed" data-toggle="collapse" href="#collapseToc" aria-expanded="false"
                    title="Catalogue" role="button">
                    <span>[&nbsp;</span><span>Catalogue</span>
                    <i class="text-collapsed icon icon-anchor"></i>
                    <i class="text-in icon icon-close"></i>
                    <span>]</span>
                </a>
            </li>
        </ul>
        <div class="bar-right">
            <div class="share-component" data-sites="weibo,qq,wechat"
                data-mobile-sites="weibo,qq,qzone"></div>
        </div>
    </div>
</nav>

</main><footer class="footer" itemscope itemtype="http://schema.org/WPFooter">
<ul class="social-links">
    <li><a href="https://gitee.com/rulerLwx" target="_blank" title="gitee" data-toggle=tooltip data-placement=top >
            <i class="icon icon-gitee"></i></a></li>
    <li><a href="https://github.com/wolf-lea" target="_blank" title="github" data-toggle=tooltip data-placement=top >
            <i class="icon icon-github"></i></a></li>
</ul>
  <div class="copyright">
    &copy;2020  -
    2020
    <div class="publishby">
        Theme by <a href="https://github.com/xiaoheiAh" target="_blank"> xiaoheiAh </a>base on<a href="https://github.com/xiaoheiAh/hugo-theme-pure" target="_blank"> pure</a>.
    </div>
  </div>
</footer>

<script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.2/MathJax.js?config=TeX-MML-AM_SVG"></script>
<script type="text/x-mathjax-config">
    MathJax.Hub.Config({
            showMathMenu: false, //disables context menu
            tex2jax: {
            inlineMath: [ ['$','$'], ['\\(','\\)'] ]
           }
    });
</script>


<script src="https://cdn.jsdelivr.net/npm/jquery@3.4.1/dist/jquery.min.js"></script>
<script>
    window.jQuery || document.write('<script src="js/jquery.min.js"><\/script>')
</script>
<script type="text/javascript" src="https://cdn.staticfile.org/highlight.js/9.15.10/highlight.min.js"></script>
<script type="text/javascript" src="https://cdn.staticfile.org/highlight.js/9.15.10/languages/python.min.js" defer></script>
<script type="text/javascript" src="https://cdn.staticfile.org/highlight.js/9.15.10/languages/javascript.min.js" defer></script><script>
    hljs.configure({
        tabReplace: '    ', 
        classPrefix: ''     
        
    })
    hljs.initHighlightingOnLoad();
</script>
<script src="https://rulerLwx.gitee.io/js/application.min.bdeb64b910570b6c41badc6a05b7afb0c8ad9efd8525de3c7257d59e786326a3.js"></script>
<script src="https://rulerLwx.gitee.io/js/plugin.min.51ff8c7317566f82259170fa36e09c4493adc9b9378b427a01ad3f017ebac7dd.js"></script>

<script>
    (function (window) {
        var INSIGHT_CONFIG = {
            TRANSLATION: {
                POSTS: 'Posts',
                PAGES: 'Pages',
                CATEGORIES: 'Categories',
                TAGS: 'Tags',
                UNTITLED: '(Untitled)',
            },
            ROOT_URL: 'https:\/\/rulerLwx.gitee.io',
            CONTENT_URL: 'https:\/\/rulerLwx.gitee.io\/searchindex.json ',
        };
        window.INSIGHT_CONFIG = INSIGHT_CONFIG;
    })(window);
</script>
<script type="text/javascript" src="https://rulerLwx.gitee.io/js/insight.min.a343cd9a5a7698336b28ef3a7c16a3a1b1d2d5fb17dc8ed04022bbe08cc5459073a15bdafa3a8a58cdd56080784bdd69fa70b1ae8597565c799c57ed00f0e120.js" defer></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/tocbot/4.4.2/tocbot.min.js"></script>
<script>
    tocbot.init({
        
        tocSelector: '.js-toc',
        
        contentSelector: '.js-toc-content',
        
        headingSelector: 'h1, h2, h3',
        
        hasInnerContainers: true,
    });
</script>

<script src="https://cdn1.lncld.net/static/js/3.0.4/av-min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/valine"></script>
<script type="text/javascript">
    var GUEST = ['nick', 'mail', 'link'];
    var meta = 'nick,mail';
    meta = meta.split(',').filter(function (item) {
        return GUEST.indexOf(item) > -1;
    });
    new Valine({
        el: '#vcomments',
        verify: null ,
        notify: null ,
        appId: 'IyAB0PSPRazTPDxitO1ddQ7O-gzGzoHsz',
        appKey: '5rBJTq4KidYF33eXwvRVhtEH',
        placeholder: 'enjoy~',
        avatar: 'mm',
        meta: meta,
        pageSize: '10' || 10,
        visitor: false 
});
</script>

  </body>
</html>
